package gri_userprefs;

use xml_helper;
use Data::Dumper;
use MIME::Base64;

my $error="";

sub get_error {
	return $error;
}

sub new_empty {
my $self={};
shift;
my $f=shift;

	$self->{filename}=$f;
	$self->{prefs}={};
	bless($self);
	return $self;
}

sub new {
my $self={};
shift;
my $f=shift;

	$self->{xml_helper}=new xml_helper();
	$self->{filename}=$f;

	my $d=""; my $fd;
	if(!open($fd,$f)) {
		$error="Can not open file '$f' : $!";
		return(undef);
	}
	$self->{prefs}={};
	$d=join("",<$fd>);
	close($fd);
	my $x=$self->{xml_helper}->parse($d);
	if(! $x) {
		$error="Unable to parse XML!";
		return undef;
	}

	# Check the data is in the format we expect.

	my ($data,$attrs,$elements)=$self->{xml_helper}->get_element("");
	# print Dumper($self->{xml_helper});
	if(! @$elements) {
		$error="Invalid data to parse [top level]";
		return(undef);
	}
	if(scalar(@$elements)!=1) {
		$error="More than 1 top level element!";
		return(undef);
	}
	if($elements->[0] ne "|userprefs#0") {
		$error="Top level element is not 'userprefs'";
	}
	my $n=0;
	while(1) {
		($data,$attrs,$elements)=$self->{xml_helper}->get_element("userprefs#0|pref#$n");
		last if !defined($data);

		#################################################################
		# We expect the title and reports elements to be here - abort	#
		# if not.							#
		#################################################################
		if(! exists($attrs->{name})) {
			$error="Missing 'name' attribute.";
			return(undef);
		}
		my ($_min,$_max,$_values)=("","","");
		$_min=$attrs->{min} if exists($attrs->{min});
		$_max=$attrs->{max} if exists($attrs->{max});
		$_values=$attrs->{values} if exists($attrs->{values});
		if(! exists($attrs->{desc})) {
			$error="Missing 'desc' attribute.";
			return(undef);
		}
		if (@$elements) {
			$error="Element 'pref' not expected to have child elements.";
			return(undef);
		}
		$self->{prefs}->{$attrs->{name}}=[$attrs->{desc},$data,$_min,$_max,$_values];
		$n++;
	}
	bless($self);
	return $self;
}

sub get_raw_pref {
my $self=shift;
my $pref=shift;

	if(exists($self->{prefs}->{$pref})) {
		my $x=$self->{prefs}->{$pref};
		return {
			key => $pref,
			desc => $x->[0],
			value => $x->[1],
			minv => $x->[2],
			maxv => $x->[3],
			vals => $x->[4],
		};
	}
	return undef;
}


sub get_pref_list {
my $self=shift;
	return keys(%{$self->{prefs}});
}

sub get_pref_value {
my $self=shift;
my $pref=shift;

	if(!exists($self->{prefs}->{$pref})) {
		return undef;
	}
	my $vv="";
	eval {$vv = decode_base64($self->{prefs}->{$pref}->[1]);};
	return($self->{prefs}->{$pref}->[0],$vv);
}

sub get_pref_desc {
my $self=shift;
my $pref=shift;

	if(!exists($self->{prefs}->{$pref})) {
		return undef;
	}
	my $vv="";
	return $self->{prefs}->{$pref}->[0];
}

sub get_pref_min_max_values {
my $self=shift;
my $pref=shift;

	if(!exists($self->{prefs}->{$pref})) {
		return undef;
	}
	my $vv="";
	return ($self->{prefs}->{$pref}->[2],
		$self->{prefs}->{$pref}->[3],
		$self->{prefs}->{$pref}->[4]);
}

sub set_pref_value {
my $self=shift;
my $pref=shift;
my $desc=shift;
my $value=shift;

	if(!exists($self->{prefs}->{$pref})) {
		if(!defined($desc)) {
			$desc="";
		}
		if(!defined($value)) {
			$value="";
		}
		$self->{prefs}->{$pref}=[$desc,encode_base64($value,"")];
		return;
	}

	$desc=$self->{prefs}->{$pref}->[0] if(!defined($desc));
	$value=$self->{prefs}->{$pref}->[1] if(!defined($value));
	my @O=@{$self->{prefs}->{$pref}}[2 .. 4];
	$self->{prefs}->{$pref}=[$desc,encode_base64($value,""),@O];
}

sub write {
my $self=shift;
my $f2=shift;

	my $f=$self->{filename};
	$f=$f2 if defined($f2);

	my $fd;
	my $tmp="$f.tmp.$$";
	if(!open($fd,">$tmp")) {
		return(0,"Unable to open '$tmp' for writing: $!");
	}
	my @H=('<?xml version="1.0" standalone="yes"?>'."\n" , "<userprefs>\n");
	my @T=("</userprefs>\n");
	for my $c (@H) {
		if(! print $fd $c) {
			close($fd);
			unlink($tmp);
			return(0,"Unable to write to file: $!");
		}
	}
	for my $ckey (keys(%{$self->{prefs}})) {
		my $str="  <pref name=\"$ckey\" desc=\"$self->{prefs}->{$ckey}->[0]\"";
		if(length($self->{prefs}->{$ckey}->[2])) {
			$str.=" min=\"$self->{prefs}->{$ckey}->[2]\"";
		}
		if(length($self->{prefs}->{$ckey}->[3])) {
			$str.=" max=\"$self->{prefs}->{$ckey}->[3]\"";
		}
		if(length($self->{prefs}->{$ckey}->[4])) {
			$str.=" values=\"$self->{prefs}->{$ckey}->[4]\"";
		}
		$str.=">" . $self->{prefs}->{$ckey}->[1];
		$str.="</pref>";
		if(! print $fd "$str\n") {
			close($fd);
			unlink($tmp);
			return(0,"Unable to write to file: $!");
		}
	}
	for my $c (@T) {
		if(! print $fd $c) {
			close($fd);
			unlink($tmp);
			return(0,"Unable to write to file: $!");
		}
	}
	if(!close($fd)) {
		close($fd);
		unlink($tmp);
		return(0,"Unable to write to file: $!");
	}

	rename($tmp,$f);
	unlink($tmp);
	return(1,undef);
}

sub get_raw_prefs {
my $self=shift;

	return $self->{prefs};
}

sub remove {
my $self=shift;
my $pref=shift;


	if(exists($self->{prefs}->{$pref})) {
		delete $self->{prefs}->{$pref};
	}
}

sub add {
my $self=shift;
my $hr=shift;

	$self->{prefs}->{$hr->{key}}=[ $hr->{desc},$hr->{value},$hr->{minv},$hr->{maxv},$hr->{vals} ];
}

# The aim here is to take the current object and compare with
# another. The compare will return two lists - one of preferences
# in the first and not in the second, and a list of those in the
# second and not the first.
#
# Typiclly used to compare user preferences with __DEFAULT__ - the
# idea being that newer preferences can be added for the user,
# and older ones removed.

sub compare {
my $self=shift;
my $other=shift;

	my @my_pref_list=();
	my @other_pref_list=();

	@my_pref_list=$self->get_pref_list();
	@other_pref_list=$other->get_pref_list();

	my @in_other_not_self=();
	my @in_self_not_other=();

	for my $ck (@my_pref_list) {
		if(! grep {$_ eq $ck} @other_pref_list) {
			my $raw=$self->get_raw_pref($ck);
			if(defined($raw)) {
				push @in_self_not_other,{%$raw};
			}
		}
	}
	for my $ck (@other_pref_list) {
		print STDERR "ck=$ck\n";
		if(! grep {$_ eq $ck} @my_pref_list) {
			my $raw=$other->get_raw_pref($ck);
			push @in_other_not_self,{%$raw};
		}
	}

	return ([@in_self_not_other],[@in_other_not_self]);
}

1;

